package com.easepal802s.project.ble;

import android.bluetooth.BluetoothGatt;
import android.os.Handler;
import android.util.Log;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleReadCallback;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.ogawa.base.Constant.BleConstant;
import com.easepal802s.project.observer.BleDataObserver;
import com.ogawa.base.utils.CommonUtil;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;


/**
 * Created by FHB on 2018/4/18.
 */
public class BleController {
    /**
     *
     *扫描及过滤过程是在工作线程中进行，所以不会影响主线程的UI操作，最终每一个回调结果都会回到主线程。
     */
    //智享椅的UUID  服务的 写的  读的
    public static final String[] ZXUUIDS = {"0000fff0-0000-1000-8000-00805f9b34fb", "8B00ACE7-EB0B-49B0-BBE9-9AEE0A26E1A3", "0734594a-a8e7-4b1a-a6b1-cd5243059a57"};
    private BleDevice mBleDevice;
    private int mConnectState;

    public static int CONNECT_SUCCEED =1;
    public static int CONNECT_ING =2;
    public static int CONNECT_FAIL =3;
    public static int CONNECT_BREAK =5;
    public static int SCANNING =6;

    private static Object mLock = new Object();
    private static BleController mInst = null;
    private static String sendCommandCache;
    private int repeatCount = 0;//连接失败重连次数
    private int repeatCount2 = 0;//断开重连次数
    private int repeatSendCount = 0;//重发次数
    private long mTime;
    private  boolean isOnReplyOk = false;
    private  boolean  isON =false;
    private boolean mShoulderAdjust =true;
    private boolean mIsScanning =false;
    private boolean isUnknowBreak; //是否是主动断开连接
    private int mReconnectCount;
    private Disposable disposableReply;
    private Disposable disposable;
    private Disposable mDisposableLong;
    private boolean hasTarget;//是否有目标蓝牙
    private boolean isConnectSucceed;
    private boolean isReseting;//是否在复位
    private String mData;
    private String mScanData ="-1";
    private String mScanAdjustData ="-1";
    private Disposable mDisposableConnect;
    private boolean hasPowerOff;
    private boolean isHome = true;
    private int skillResult=-1;
    private int AutoResult=-1;
    private int AirResult=-1;
    private String autoName;
    private String autoCommond;
    private BleController(){
//        mUserInfoActions = new ArrayList<OnUserInfoAction>();
    }

    public static BleController getInst(){
                if(mInst == null){
                    mInst = new BleController();
        }
        return mInst;
    }
    public void setIsHome(boolean ishome){
        isHome = ishome;
    }
    public boolean getIsHome(){
        return isHome;
    }

    public void setConnect(int state){
        mConnectState = state;
    }
    public int getConnectState(){
        return mConnectState;
    }
    public boolean getIsCanAdjust(){
        return mShoulderAdjust;
    }
    public void setIsCanAdjust(boolean isCanAdjust){
        mShoulderAdjust =isCanAdjust;
    }
    public  boolean getIsReseting(){
        return  isReseting;
    }
    public boolean getIsScanning(){
        return mIsScanning;
    }
    public void setIsScanning(boolean isScan){
        mIsScanning =isScan;
    }



    public boolean getIsOn(){
        return isON;
    }
    public void setIsOn(boolean flag){
        isON = flag;
    }
    public void scanDevice(){
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanStarted(boolean success) {
                // 开始扫描（主线程）
                hasTarget = false;
                BleDataObserver.getInst().noticeStarScan();
                setConnect(SCANNING);
                Log.e("scanDevice+Started","onScanStarted");
            }

            @Override
            public void onScanning(BleDevice bleDevice) {

              Log.e("scanDevice+Scaning",bleDevice.getName()+"");
              //&&bleDevice.getName().contains("MC")
              if(bleDevice.getName() != null){
                  hasTarget = true;
                  BleDataObserver.getInst().noticeDeviceFind(bleDevice);
                  stopScan();
              }
          }

//            }

            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                 if(scanResultList==null||scanResultList.size()==0){
                     BleDataObserver.getInst().noticeNoDeviceFind();
                 }
                 if(!hasTarget){
                     BleDataObserver.getInst().noticeDeviceFind(null);
                 }

                Log.e("scanDevice+Finished",scanResultList.size()+"");
                // 扫描结束，列出所有扫描到的符合扫描规则的BLE设备（主线程）
            }
        });
    }




    public BleDevice getDevice(){
        return mBleDevice;
    }
    public boolean isConnectSucceed(){
        return  isConnectSucceed;
    }

    /**
     *
     * 在哪个线程中进行连接，结果就回到那个线程中回调
     * 但是在某些型号手机上，connectGatt必须在主线程才能有效。
     * 非常建议把连接过程放在主线程。
     * 关于重连：连接断开之后如果需要重连。可以在onDisConnected回调方法中再次调用connect方法。为保证重连成功率，
     * 建议间隔一段时间之后进行重连。
     * @param bleDevice
     */
    public void connectDevice(final BleDevice bleDevice){
        BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
            @Override
            public void onStartConnect() {
                // 开始连接
                setConnect(CONNECT_ING);
                if(!isUnknowBreak){
                    BleDataObserver.getInst().noticeConnectStateChange(CONNECT_ING);
                }

                Log.e("connectDevice","onStartConnect");
            }
            @Override
            public void onConnectFail(BleDevice bleDevice,BleException exception) {
                isConnectSucceed = false;
                setConnect(CONNECT_FAIL);
                // 连接失败
                if(repeatCount<10){
                    repeatCount++;
                    new Handler().postDelayed(new Runnable() {
                        public void run() {
                            // 连接失败

                            connectDevice(bleDevice);

                        }

                    }, 200);
                }
                else {
                    mBleDevice = null;
                    BleDataObserver.getInst().noticeConnectStateChange(CONNECT_FAIL);

                }




                Log.e("connectDevice","onConnectFail+"+exception.toString());
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接成功，BleDevice即为所连接的BLE设备
                Log.e("connectDevice","onConnectSuccess");
                setConnect(CONNECT_SUCCEED);
                isConnectSucceed = true;
                repeatCount = 0;
                repeatCount2 = 0;
                mBleDevice = bleDevice;
                //如果不是断线重连的就做提示
                if(!isUnknowBreak){
                    BleDataObserver.getInst().noticeConnectStateChange(CONNECT_SUCCEED);
                }
                hasPowerOff =false;

                readData();
                getDataNotify();
                notifyConntet();
            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, final BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法  关闭蓝牙 false
                Log.e("connectDevice","onDisConnected+"+isActiveDisConnected);

                isConnectSucceed = false;
                setConnect(CONNECT_BREAK);
                if(!isActiveDisConnected&&BleManager.getInstance().isBlueEnable()){
                    isUnknowBreak = true;//b
                    if(repeatCount2<10){
                        repeatCount2++;
                        new Handler().postDelayed(new Runnable() {
                            public void run() {
                                // 连接失败
                                connectDevice(bleDevice);

                            }

                        }, 200);
                    }
                    else {
                        connectBreak();
                    }
                }
                else {
                    Log.e("connectDevice222","onDisConnected+"+isActiveDisConnected);
                    isUnknowBreak =false;
                    connectBreak();

                }
            }
        });
    }
    public void connectBreak(){
        if(mBleDevice!=null){
            disconnect();
            mBleDevice = null;
        }
        hasPowerOff = true;
        BleController.getInst().setConnect(CONNECT_BREAK);
        BleDataObserver.getInst().noticePowerOff();
        BleController.getInst().stopScan();
        BleController.getInst().stopNotify();
        BleController.getInst().stopAllWrite();

        BleDataObserver.getInst().noticeConnectStateChange(CONNECT_BREAK);
    }

    /**
     * 调用该方法后，如果当前还处在扫描状态，会立即结束，并回调onScanFinished方法。
     */
    public void stopScan(){
        BleManager.getInstance().cancelScan();

    }

    /**
     * 断开某个设备
     */
    public void disconnect(){
        BleManager.getInstance().disconnect(mBleDevice);

    }


    public  void notifyConntet() {
        Observable.interval(0, 300, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                   mDisposableConnect = d;

                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {

                        if(!BleManager.getInstance().isConnected(mBleDevice)&&!hasPowerOff){
                            Log.e("Noticififif","aaaa"+hasPowerOff);

                            BleController.getInst().connectBreak();
                            isUnknowBreak = true;//b
                            if(mDisposableConnect!=null){
                                mDisposableConnect.dispose();
                            }
                        }

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }


    /**
     * （方法说明）订阅通知notify
     */
    private void getDataNotify(){
        BleManager.getInstance().notify(mBleDevice,
                ZXUUIDS[0],
                ZXUUIDS[2],
                new BleNotifyCallback() {
                    @Override
                    public void onNotifySuccess() {
                        // 打开通知操作成功
                    }

                    @Override
                    public void onNotifyFailure(BleException exception) {
                        // 打开通知操作失败
                    }

                    @Override
                    public void onCharacteristicChanged(byte[] data) {
                        // 打开通知后，设备发过来的数据将在这里出现
                        String respone = HexUtils.getHexString(data, 0, data.length, false);
                        distributeData(respone);
                    }
                });
    }

    /**
     * 取消订阅通知notify，并移除数据接收的回调监听
     */
    public void stopNotify(){
        BleManager.getInstance().stopNotify(mBleDevice, ZXUUIDS[0],ZXUUIDS[2]);

    }



    public void writeDatas(byte[] data){
        BleManager.getInstance().write(
                mBleDevice,
                ZXUUIDS[0],
                ZXUUIDS[1],
                data,
                new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(int current, int total, byte[] justWrite) {
                        Log.e("onWriteSuccess",Arrays.toString(justWrite));
                        // 发送数据到设备成功
                    }

                    @Override
                    public void onWriteFailure(BleException exception) {
                        // 发送数据到设备失败
                    }
                });
    }

    public synchronized void sendSingleData(final String data, final boolean isRepeat) {
     Log.e("sendSingleData",data);
        stopReplyOk();
        Observable.timer(0, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                            singleDataOption(data, true);
                            d.dispose();

                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }


    public synchronized void sendSingleData(final String data,long delay, final boolean isRepeat) {
        Log.e("sendSingleData",data);
        stopReplyOk();
        Observable.timer(delay, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        singleDataOption(data, true);
                        d.dispose();

                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }



    public synchronized void sendLongclickSingleData(final String data, final boolean isRepeat) {
        Log.e("sendLongSingleData",data);
        stopReplyOk();
        Observable.timer(1, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        writeDatas(HexUtils.hexToByte(CommonUtil.toSingleCommand(data)));
                        d.dispose();

                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }

    private void singleDataOption(String data, boolean isRepeat) {

        writeDatas(HexUtils.hexToByte(CommonUtil.toSingleCommand(data)));
        if (isRepeat) {
            sendCommandCache = data;
            repeat(data);
        } else {
            sendCommandCache = null;
        }

    }


    public void distributeData(String datas) {
        mayBeCanclepeat(datas);
        synBleState(datas);
        BleDataObserver.getInst().noticeGetData(datas);
        Log.e("distributeData",isOnReplyOk+"");
        if(!isOnReplyOk){
            Log.e("distributeData222","setIsOnReplyOk");
            sendReplyOk();
        }

    }
    public void setIsOnReplyOk(){
        Log.e("setIsOnReplyOk","setIsOnReplyOk");
        isOnReplyOk = false;
    }
    public void stopLong(){

    }
    public void stopReplyOk(){
        if(disposableReply!=null){
            isOnReplyOk = true;
            disposableReply.dispose();
        }
    }

    private void synBleState(String data) {
        if(mData==null||!mData.equals(data)){
            mData = data;
            Log.e("getDatas00",data);
            if (data.startsWith(BleConstant.BAG1_HEAD)) {

                if (!mScanData.equals(HexUtils.getByteInPosition(data, 4, 4))) {
                    mScanData = HexUtils.getByteInPosition(data, 4, 4);

                    if (mScanData.equals("1")) {
                        setIsScanning(true);
                    }
                    else {
                        setIsScanning(false);
                    }

                }
                if (!mScanAdjustData.equals(HexUtils.getByteInPosition(data, 4, 6))) {
                    mScanAdjustData = HexUtils.getByteInPosition(data, 4, 6);

                    if (mScanAdjustData.equals("1")) {
                        BleDataObserver.getInst().noticeShoulderAdjust(1);

                    }
                    else {
                    }

                }

                //第一包数据
                byte[] buffer = HexUtils.hexToByte(data);
                byte bytes5 = buffer[5];//按摩手法
                byte bytes6 = buffer[6];//按摩手法
                skillResult= bytes5+bytes6;
                //====buffer[3] ----对应block0.要扣除前面的7B(BYTE 0) B1(BYTE 1) OC(BYTE 2)
                //byte4  bit0 = 1系统正在运行
                if (HexUtils.getByteInPosition(buffer[3],0).equals("1")) {
                    isON = true;

                } else {
                    if(isON){
                        isON = false;
                        Log.e("onPowerOffaaa11","onPowerOff");
                        BleDataObserver.getInst().noticePowerOff();

                    }

                }
            }

           else if (data.startsWith(BleConstant.BAG2_HEAD)) {
                byte[] buffer = HexUtils.hexToByte(data);
                byte byte5 =buffer[5];
                byte byte6 =buffer[6];
                byte byte10 =buffer[10];
                byte byte7 =buffer[7];
                AutoResult = byte5+byte6+byte10;
                AirResult = byte7;
                Log.e("changeeee",byte5+"=="+byte6+"==="+byte10);
                //上班族
                if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,2))){
                    autoName ="上班族";
                    autoCommond =BleConstant.SHANGBZ;
                }
                //低头
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,3))){
                    autoName ="低头族";
                    autoCommond =BleConstant.DiTZ;

                }
                //开车
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,4))){
                    autoName ="开车族";
                    autoCommond =BleConstant.DiTZ;

                }
                //高跟
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,5))){
                    autoName ="高跟族";
                    autoCommond =BleConstant.GAOGZ;

                }
                //清晨唤醒
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,4))){
                    autoName ="清晨唤醒";
                    autoCommond =BleConstant.QINGCHX;
                }
                //午间小休
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,10,0))){
                    autoName ="午间小休";
                    autoCommond =BleConstant.WUJXX;
                }
                //舒眠模式
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,5))){
                    autoName ="舒眠模式";
                    autoCommond =BleConstant.SHUMMS;
                }

                //女王美体
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,10,1))){
                    autoName ="女王美体";
                    autoCommond =BleConstant.NVWMT;
                }
                //男士健体
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,10,2))){
                    autoName ="男士健体";
                    autoCommond =BleConstant.NANSJT;
                }
                //老年模式
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,1))){
                    autoName ="老年模式";
                    autoCommond =BleConstant.LAONMS;
                }

                //速按放松
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,3))){
                    autoName ="速按放松";
                    autoCommond =BleConstant.SUAFS;
                }
                //深度放松
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,1))){
                    autoName ="深度放松";
                    autoCommond =BleConstant.SHENDFS;

                }
                //久坐释压
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,10,3))){
                    autoName ="久坐释压";
                    autoCommond =BleConstant.JIUZSY;
                }

                //全身舒展
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,0))){
                    autoName ="全身舒展";
                    autoCommond =BleConstant.QUANSSZ;
                }
                //运动恢复
                else if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,6,0))){
                    autoName ="运动恢复";
                    autoCommond =BleConstant.YUNDHF;
                }
                //泰式拉伸
                else  if(CommonUtil.isOpera(HexUtils.getByteInPosition(data,5,2))){
                    autoName ="泰式拉伸";
                    autoCommond =BleConstant.TAISLS;
                }
                BleDataObserver.getInst().noticeDataChange("2",AutoResult,skillResult,AirResult,autoName,autoCommond);

            }

            else  if (data.startsWith(BleConstant.PING)) {

                setIsScanning(false);
                if(isON){
                    BleDataObserver.getInst().noticePowerOff();
                    isON = false;
                }


            }
        }

    }
    // 回应之后取消重发
    private void mayBeCanclepeat(String datas) {
        if (datas.length() == 10 && sendCommandCache != null) {
            if (datas.substring(6, 8).equals(sendCommandCache)) {
                Log.e("mayBeCanclepeat",sendCommandCache+"");
                  isOnReplyOk = false;
                if (disposable != null) {
                    disposable.dispose();
                }
            }
        }
        if (datas.startsWith(BleConstant.BAG3_HEAD)) {
            if (datas.substring(12, 14).equals("01")) {
                isReseting = false;
            }
            else  if (datas.substring(12, 14).equals("00")) {
                isReseting = true;
            }
        }

    }


    public void stopAllWrite(){
        isReseting = false;
        if(disposableReply!=null){
            isOnReplyOk = false;
            disposableReply.dispose();
        }
        if(disposable!=null){
            disposable.dispose();
        }
        setConnect(CONNECT_BREAK);
       repeatCount = 0;
       repeatCount2 = 0;
    }


    public synchronized void sendReplyOk() {
        isOnReplyOk = true;
        Observable.interval(500, 500, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                         disposableReply = d;
                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {
                        Log.e("sendReplyOk","sendReplyOk");
                        writeDatas(HexUtils.hexToByte(BleConstant.PONG));

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }


    //重发机制
    private void repeat(final String data) {
        Log.e("repeatdata000",data);
        repeatSendCount = 0;
        if(disposable!=null){
            disposable.dispose();
        }
        Observable.interval(1000, 200, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onNext(@NonNull Long aLong) {
                        if (repeatSendCount < 10) {
                            Log.e("repeatdata111",data);
                            writeDatas(HexUtils.hexToByte(CommonUtil.toSingleCommand(data)));
                            repeatSendCount++;

                        } else {
                            disposable.dispose();
                            isOnReplyOk = false;
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }


    public void readData(){
        BleManager.getInstance().read(
                mBleDevice,
                ZXUUIDS[0],
                ZXUUIDS[1],
                new BleReadCallback() {
                    @Override
                    public void onReadSuccess(byte[] data) {
                        // 读特征值数据成功
                        Log.e("readData",Arrays.toString(data)+"");
                    }

                    @Override
                    public void onReadFailure(BleException exception) {
                        Log.e("readData",exception.toString()+"");
                        // 读特征值数据失败
                    }
                });
    }




}
